package com.pi.dc.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import com.pi.base.util.bean.ObjectTool;
import com.pi.base.util.time.DateTools;
import com.pi.dc.dao.entity.DcDeviceInfoEntity;
import com.pi.dc.dao.entity.HcUserSleepRollLogEntity;
import com.pi.dc.dao.mapper.HcUserSleepRollLogMapper;
import com.pi.dc.dao.param.HcUserSleepRollLogParam;
import com.pi.dc.dao.param.HcUserSleepRollLogQuery;
import com.pi.dc.enumerate.DcDevTypeEnum;
import com.pi.dc.enumerate.SleepInfoLevel;
import com.pi.dc.model.DatedSleepInfoNode;
import com.pi.dc.model.UserSleepInfo;
import com.pi.dc.smart.SmartConstants;
import com.pi.dc.vo.UserSleepInfoVo;
import com.pi.smart.client.ins.bed.domain.SmartBedRoutineResponse;

@Validated
@Service
public class HcUserSleepLogService {
  
  private static final Logger logger = LoggerFactory.getLogger(HcUserSleepLogService.class);
  private static final int DAY_MAX_INTERVAL = 3600 *24; //日内最大间隔是1天, 超过1天则默认为为按天统计
  private static int DEFAULT_SLEEP_QUALITY = 70;
  private static int DEFAULT_MAX_SLEEP_QUALITY = 75;
  private static int MAX_SLEEP_QUALITY = 95;
  private static int LOWEST_SLEEP_QUALITY = 65;
  @Autowired
  private HcUserSleepRollLogMapper userSleepRollLogMapper;
  @Autowired
  private DcDeviceInfoService devInfoService;
  
  public UserSleepInfoVo queryUserSleepVo(
      Long userId, Long bedId, 
      Date start, Date end, Integer interval){
    List<HcUserSleepRollLogEntity> list = queryUserSleepInfo(userId, bedId, start, end);
    //获取间隔的列表
    List<Date> intervalList = getIntervalList(start, end, interval);
    
    //构造时间对象
    return transRollLogEntityToVo(list, intervalList, 
        (interval >= DAY_MAX_INTERVAL)? SleepInfoLevel.LEVEL_DAY : SleepInfoLevel.LEVEL_HOUR, interval);
  }

  public void insertUserSleepRollLog(String devCode, Long ts){
    insertUserSleepRollLog(devCode, 1, ts);
  }
  
  public void insertUserSleepRollLog(String devCode, int rollingTimes){
    insertUserSleepRollLog(devCode, rollingTimes, null);
  }
  
  private void insertUserSleepRollLog(String devCode, int rollingTimes, Long ts){
    //查询设备的信息
    DcDeviceInfoEntity devInfo = devInfoService.getByDevCodeIfExist(devCode, DcDevTypeEnum.SMART_BED.getType());
    if(null == devInfo){
      logger.error("设备{}的信息不存在", devCode);
      return;
    }
    HcUserSleepRollLogEntity entity = new HcUserSleepRollLogEntity();
    entity.setBedId(devInfo.getId());
    entity.setUserId(devInfo.getOwnerId());
    entity.setRollingTimes(rollingTimes);
    if(null != ts){
      entity.setCreateDate(new Date(ts));
      entity.setUpdateDate(entity.getCreateDate());
    }
    userSleepRollLogMapper.insert(entity);
  }
  
  public void insertUserSleepRollLogBatch(List<SmartBedRoutineResponse> responseList) {
    if(CollectionUtils.isEmpty(responseList)) {
      return;
    }
    //查询设备的信息
    DcDeviceInfoEntity devInfo = devInfoService.getByDevCodeIfExist(responseList.get(0).getDevId(), DcDevTypeEnum.SMART_BED.getType());
    if(null == devInfo){
      logger.error("设备{}的信息不存在", responseList.get(0).getDevId());
      return;
    }
    List<HcUserSleepRollLogEntity> list = new ArrayList<>(responseList.size());
    for(SmartBedRoutineResponse smartBedRoutineResponse:responseList) {
      HcUserSleepRollLogEntity entity = new HcUserSleepRollLogEntity();
      entity.setBedId(devInfo.getId());
      entity.setUserId(devInfo.getOwnerId());
      entity.setRollingTimes(smartBedRoutineResponse.getRollingTimes());
      if(null != smartBedRoutineResponse.getTs()){
        entity.setCreateDate(new Date(smartBedRoutineResponse.getTs()));
        entity.setUpdateDate(entity.getCreateDate());
      }
      list.add(entity);
    }
    userSleepRollLogMapper.batchAdd(list);
  }
  
  private List<Date> getIntervalList(Date start, Date end, Integer interval){
    List<Date> intervalList = new ArrayList<>();
    for(int i =0; (start.getTime() + interval * i*1000L) <= end.getTime(); i++ ){
      intervalList.add(new Date(start.getTime() + interval * i*1000L + 1000L));
    }
    return intervalList;
  }
  
  private UserSleepInfoVo transRollLogEntityToVo(
      List<HcUserSleepRollLogEntity> list, List<Date> intervalList, SleepInfoLevel level, Integer interval){
    if(CollectionUtils.isEmpty(list)){
      UserSleepInfoVo sleepInfoVo = new UserSleepInfoVo();
      sleepInfoVo.setDateDesc(new String[0]);
      sleepInfoVo.setSleepQuality(new int[0]);
      sleepInfoVo.setOverAll("0.0分");
      return sleepInfoVo;
    }
    List<DatedSleepInfoNode> sleepNodes = generateDataNode(list, intervalList);
    return transDatedSleepInfoNodeToVo(sleepNodes, level, interval);
  }
  
  private UserSleepInfoVo transDatedSleepInfoNodeToVo(List<DatedSleepInfoNode> sleepNodes, SleepInfoLevel level, Integer interval){
    UserSleepInfoVo vo = new UserSleepInfoVo();
    String[] dateDesc = new String[sleepNodes.size()];
    int[] quality = new int[sleepNodes.size()];
    int index = sleepNodes.size() - 1;
    int sum = 0;
    int count = 0;
    UserSleepInfo baseSleepLine = findBaseLine(sleepNodes.get(0).getUserSleepRollList().get(0).getUserId(), sleepNodes.get(0).getUserSleepRollList().get(0).getBedId(), interval);
    
    for(DatedSleepInfoNode sleepNodeInfo: sleepNodes){
      Calendar cal = Calendar.getInstance();
      cal.setTime(sleepNodeInfo.getDate());
      int unitbody;
      if(level == SleepInfoLevel.LEVEL_DAY){
        unitbody = cal.get(Calendar.DATE);
      }else{
        unitbody = cal.get(Calendar.HOUR_OF_DAY);
      }
      
      dateDesc[index] = unitbody + level.getUnit();
      quality[index] = getSleepQuality(sleepNodeInfo.getUserSleepRollList(), baseSleepLine, interval);
      vo.setDateDesc(dateDesc);
      vo.setSleepQuality(quality);
      if(quality[index] > 0) {
        sum += quality[index];
        count ++;
      }
      index --;
    }
    //计算平均分
    vo.setOverAll(count > 0 ?(sum/count) + "分" : "0.0分");
    return vo;
  }
  /**
   * @description 如果是第一次， 会将当晚的首个点作为基准
   * @param list
   * @param defaultBaseList 基准
   * @param interval 
   * @return
   */
  private int getSleepQuality(List<HcUserSleepRollLogEntity> list, UserSleepInfo baseSleepLine, Integer interval) {
    if(CollectionUtils.isEmpty(list)){
      return 0;
    }
    int rollings = getRollingsFromList(list);
    int quality = 0;
    if(null == baseSleepLine){
      //无记录的则以最高75分计数
      int baseRollings = getRollingsFromList(list);
      int scape = (rollings - baseRollings) * 5/16;
      quality = DEFAULT_SLEEP_QUALITY - scape;
      if(quality > DEFAULT_MAX_SLEEP_QUALITY){
        quality = DEFAULT_MAX_SLEEP_QUALITY;
      }
      if(quality < LOWEST_SLEEP_QUALITY){
        quality = LOWEST_SLEEP_QUALITY;
      }
    }else{
      quality = baseSleepLine.getOverAll() - (rollings - baseSleepLine.getAverageRollings()) * 5;
    }
    return (quality > MAX_SLEEP_QUALITY) ? 
        MAX_SLEEP_QUALITY : 
          (quality < LOWEST_SLEEP_QUALITY) ? LOWEST_SLEEP_QUALITY : quality;
  }
  
  private int getRollingsFromList(List<HcUserSleepRollLogEntity> list){
    int rollings = 0;
    for(HcUserSleepRollLogEntity entity : list){
      rollings += entity.getRollingTimes();
    }
    return rollings;
  }
  
  private UserSleepInfo findBaseLine(Long userId, Long bedId, Integer interval){
    HcUserSleepRollLogParam param = new HcUserSleepRollLogParam();
    param.setUserId(userId);
    param.setBedId(bedId);
    param.setPageSize(1);
    param.setOrderParam("create_date");
    param.setOrderOperator("ASC");
    List<HcUserSleepRollLogEntity> list = userSleepRollLogMapper.findList(param);
    HcUserSleepRollLogEntity entity =  ObjectTool.getOne(list);
    if(null == entity)
      return null;
    Date start = DateTools.getDateBegin(entity.getCreateDate());
    Date end = DateTools.getDateEnd(entity.getCreateDate());
    List<HcUserSleepRollLogEntity> baseList = queryUserSleepInfo(userId, bedId, start, end);
    //设置平均翻转线和基础分数 70
    UserSleepInfo info = new UserSleepInfo();
    info.setAverageRollings(getAverageRollings(baseList, start, interval));
    info.setOverAll(DEFAULT_SLEEP_QUALITY);
    return info;
  }

  private int getAverageRollings(List<HcUserSleepRollLogEntity> baseList, Date queryStart, Integer interval) {
    Date start = null;
    Date end = null;
    Calendar cal = Calendar.getInstance();
    int bedRolls = 0;
    Set<Long> hourList = new HashSet<>();
    for(HcUserSleepRollLogEntity entity:baseList){
      cal.setTime(entity.getCreateDate());
      if(cal.get(Calendar.HOUR_OF_DAY) < 24){
        if(start == null){
          start = entity.getCreateDate();
        }
        if(start.getTime() > entity.getCreateDate().getTime()){
          start = entity.getCreateDate();
        }
        if(end == null){
          end = entity.getCreateDate();
        }
        if(end.getTime() < entity.getCreateDate().getTime()){
          end = entity.getCreateDate();
        }
        bedRolls += entity.getRollingTimes();
        hourList.add(((cal.getTimeInMillis() - queryStart.getTime())/1000)/interval);
      }
    }
    if(null != start && null != end && bedRolls != 0){
      return bedRolls/hourList.size();
    }
    return 0;
  }

  private List<DatedSleepInfoNode> generateDataNode(
      List<HcUserSleepRollLogEntity> list, List<Date> intervalList){
    int intervalIndex = intervalList.size() - 1;
    int logIndex = list.size() - 1;
    List<DatedSleepInfoNode> nodes = new ArrayList<>();
    list.sort((o1, o2) -> (Long.valueOf(o1.getCreateDate().getTime() - o2.getCreateDate().getTime()).intValue()));
    while(intervalIndex >= 0 && logIndex >=0){
      if(list.get(logIndex).getCreateDate().getTime() > intervalList.get(intervalIndex).getTime()){
        DatedSleepInfoNode require = null;
        if(nodes.size() > 0){
          DatedSleepInfoNode maxNode = nodes.get(nodes.size() -1);
          if(maxNode.getDate() == intervalList.get(intervalIndex)){
            require = maxNode;
          }
        }
        
        if(null == require){
          require = new DatedSleepInfoNode();
          require.setDate(intervalList.get(intervalIndex));
          require.setUserSleepRollList(new ArrayList<>());
          nodes.add(require);
        }
        require.getUserSleepRollList().add(list.get(logIndex));
        logIndex--;
      }else {
        intervalIndex --;
      }
    }
    return nodes;
  }
  
  private List<HcUserSleepRollLogEntity> queryUserSleepInfo(
      Long userId, Long bedId, 
      Date start, Date end){
    HcUserSleepRollLogQuery param = new HcUserSleepRollLogQuery();
    param.setBedId(bedId);
    param.setUserId(userId);
    param.setStartDate(start);
    param.setEndDate(end);
    param.setOrderParam("create_date");
    List<HcUserSleepRollLogEntity> list = userSleepRollLogMapper.queryUserSleepRollLog(param);
    return list;
  }
  
  public int getUserSleepQualityOvernumber(Long loginUserId) {
    List<DcDeviceInfoEntity> list = devInfoService.queryUserDevInfo(loginUserId);
    if(CollectionUtils.isEmpty(list)){
      return 0;
    }
    //查询设备当日的睡眠
    UserSleepInfoVo userSleepVo = queryUserSleepVo(loginUserId, list.get(0).getId(), 
        DateTools.getDateBegin(new Date()), DateTools.getDateEnd(new Date()), 3600);
    if(null == userSleepVo.getSleepQuality() || userSleepVo.getSleepQuality().length <=2){
      return 0;
    }
    Long sleepQuality = 10 * (DateTools.getDateInterval(SmartConstants.START_CAL_DATE, new Date())) + 803 + Double.valueOf(userSleepVo.getOverAll().replaceAll("[^\\d\\.]", "")).intValue();
    return sleepQuality.intValue();
  }

}
